/**
 * 认证控制器
 * @module controllers/auth
 */

const bcrypt = require('bcrypt');
const User = require('../models/user.model');
const jwtUtils = require('../utils/jwt.utils');

/**
 * 用户注册
 * @param {Object} req - Express请求对象
 * @param {Object} res - Express响应对象
 * @param {Function} next - Express下一个中间件函数
 */
exports.register = async (req, res, next) => {
  try {
    // 从请求体中获取数据
    const { username, email, password } = req.body;

    // 创建新用户
    const newUser = await User.create({ username, email, password });

    // 返回成功响应
    res.status(201).json({
      code: 201,
      message: '注册成功',
      data: newUser
    });
  } catch (error) {
    // 如果是已知错误（如用户名已存在）
    if (error.message === '用户名已存在' || error.message === '邮箱已被使用') {
      return res.status(400).json({
        code: 400,
        message: error.message,
        errors: [{
          field: error.message.includes('用户名') ? 'username' : 'email',
          message: error.message
        }]
      });
    }

    // 其他错误交给全局错误处理器处理
    next(error);
  }
};

/**
 * 用户登录
 * @param {Object} req - Express请求对象
 * @param {Object} res - Express响应对象
 * @param {Function} next - Express下一个中间件函数
 */
exports.login = async (req, res, next) => {
  try {
    // 从请求体中获取数据
    const { username, password } = req.body;

    // 查找用户
    const user = await User.findByUsername(username);

    // 如果用户不存在
    if (!user) {
      return res.status(401).json({
        code: 401,
        message: '用户名或密码错误',
        errors: []
      });
    }

    // 验证密码
    const isPasswordValid = await bcrypt.compare(password, user.password);
    if (!isPasswordValid) {
      return res.status(401).json({
        code: 401,
        message: '用户名或密码错误',
        errors: []
      });
    }

    // 更新最后登录时间
    const now = new Date().toISOString();
    await User.update(user.id, { lastLogin: now });

    // 生成令牌
    const isAdmin = user.isAdmin === 1; // 确保从数据库中读取了管理员状态
    const payload = {
      id: user.id,
      username: user.username,
      isPro: user.isPro,
      isAdmin: isAdmin
    };
    
    const token = jwtUtils.generateAccessToken(payload);
    const refreshToken = jwtUtils.generateRefreshToken(payload);

    // 返回响应
    delete user.password; // 移除密码
    
    // 确保格式化日期以符合期望格式
    const registerDate = user.registerDate ? user.registerDate.split('T')[0] : null;
    const proExpiryDate = user.proExpiryDate ? user.proExpiryDate : null;
    
    res.status(200).json({
      code: 200,
      message: '登录成功',
      data: {
        token,
        refreshToken,
        expiresIn: 3600, // 1小时
        user: {
          id: user.id,
          username: user.username,
          email: user.email,
          role: isAdmin ? 'admin' : 'user', // 添加角色字段
          isPro: user.isPro ? true : false,
          proExpiryDate: proExpiryDate,
          registerDate: registerDate,
          lastLogin: now
        }
      }
    });
  } catch (error) {
    console.error('登录失败:', error);
    next(error);
  }
};

/**
 * 刷新访问令牌
 * @param {Object} req - Express请求对象
 * @param {Object} res - Express响应对象
 * @param {Function} next - Express下一个中间件函数
 */
exports.refreshToken = async (req, res, next) => {
  try {
    // 从请求体中获取刷新令牌
    const { refreshToken } = req.body;

    // 验证刷新令牌
    const decoded = jwtUtils.verifyRefreshToken(refreshToken);
    
    if (!decoded) {
      return res.status(401).json({
        code: 401,
        message: '无效的刷新令牌',
        errors: []
      });
    }

    // 查找用户
    const user = await User.findById(decoded.id);
    
    if (!user) {
      return res.status(401).json({
        code: 401,
        message: '用户不存在',
        errors: []
      });
    }

    // 生成新的令牌
    const payload = {
      id: user.id,
      username: user.username,
      isPro: user.isPro
    };
    
    const newToken = jwtUtils.generateAccessToken(payload);
    const newRefreshToken = jwtUtils.generateRefreshToken(payload);

    // 返回响应
    res.status(200).json({
      code: 200,
      message: '令牌刷新成功',
      data: {
        token: newToken,
        refreshToken: newRefreshToken,
        expiresIn: 3600 // 1小时
      }
    });
  } catch (error) {
    next(error);
  }
}; 